home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
system
/
stepdos.zip
/
STEPDOS.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-11-08
|
68KB
|
2,511 lines
;
; ***********************************************************
; * *
; * S T E P D O S *
; * *
; * Rev 1.0 *
; * *
; * Nov 7, 1987 *
; * *
; * Mike Parker - CIS 70270,161 *
; * *
; * This program allows you to step through the execution *
; * of another program by intercepting all calls to DOS *
; * INT 21H. A window will pop up displaying all register *
; * values and a short description of the DOS function *
; * being called. Program execution will continue when *
; * you press a key. You can optionally break again after *
; * the DOS function completes so you can see the result *
; * code in the AX register along with important flags. *
; * *
; ***********************************************************
;
; To run, type STEPDOS <filename>
; where <filename> is the full pathname of an EXE or COM file.
;
PAGE 60,132
TITLE 'Step DOS Calls'
NAME STEPDOS
TESTING EQU 0
BG EQU 10H ; BG sets background color (10h = BLUE)
BLACK EQU 00H + BG
BLUE EQU 01H + BG
GREEN EQU 02H + BG
CYAN EQU 03H + BG
RED EQU 04H + BG
MAGENTA EQU 05H + BG
BROWN EQU 06H + BG
WHITE EQU 07H + BG
GRAY EQU 08H + BG
LTBLUE EQU 09H + BG
LTGREEN EQU 0AH + BG
LTCYAN EQU 0BH + BG
LTRED EQU 0CH + BG
LTMAGENTA EQU 0DH + BG
YELLOW EQU 0EH + BG
HIWHITE EQU 0FH + BG
;
CR EQU 13
LF EQU 10
BIGR EQU 1352H ; 'R' key
SMALLR EQU 1372H ; 'r'
BIGS EQU 1F53H ; 'S' key
SMALLS EQU 1F73H ; 's'
ESCAPE EQU 011BH
HOME EQU 4700H
UPARROW EQU 4800H
PGUP EQU 4900H
LEFTARROW EQU 4B00H
RIGHTARROW EQU 4D00H
XEND EQU 4F00H
DOWNARROW EQU 5000H
PGDN EQU 5100H
;
BLANK EQU 32
BRDROW EQU 205
BRDCOL EQU 186
ULC EQU 201
URC EQU 187
LLC EQU 200
LRC EQU 188
;
REGBX EQU 00 ; offsets on saved register stack
REGCX EQU 02
REGDX EQU 04
REGDI EQU 06
REGSI EQU 08
REGBP EQU 10
REGES EQU 12
REGFL EQU 14
;
IF TESTING
INT21OFF EQU 0e0h*4 ; during testing an unused INT is used
ELSE
INT21OFF EQU 21h*4
ENDIF
Code SEGMENT PUBLIC PARA 'CODE'
ASSUME CS:Code, DS:Code
Main: ; starting point
mov DI,DS
mov BX,2
mov SI,[BX] ; paragraphs of memory in system from PSP
sub SI,DI ; paragraphs beyond segment
cmp SI,1000h ; more than 64K available ?
jb main_1
mov SI,1000h ; yes, only use 64K
main_1:
add SI,DI ; si = DS + number paragraphs in DS
mov BX,ES ; bx = PSP base
sub BX,SI
neg BX ; bx = number of paragraphs needed
mov AH,4ah ; modify memory block size
int 21h
;
; Copy command line from PSP to local area
;
mov AX,CS
mov ES,AX ; change ES to be local area
;
mov SI,80h
mov CL,[SI] ; get command line character count
or CL,CL ; zero char count in cmd line?
jnz notzcl
mov AX,CS
mov DS,AX
mov DX,OFFSET Umsg
mov AH,9
int 21h
jmp exit
notzcl:
xor CH,CH
inc SI
mov DI,OFFSET PSPstr
rep movsb ; copy command line
xor AL,AL
stosb ; <NULL> terminator at end
;
mov BX,002ch
mov BX,[BX] ; get segment addr of environment from PSP
;
mov AX,CS
mov DS,AX
mov SegEnv,BX ; save in EXEC control block
;
mov DX,OFFSET INITmsg
mov AH,9
int 21h
;
; Calculate starting address on screen for window
;
mov BX,OFFSET W1 ; window parameters
mov AX,[BX].leftrow
mul BytesPL ; multiply by bytes per line
mov CX,[BX].leftcol
shl CX,1 ; times 2 for attribute byte
add AX,CX
mov SI,AX ; starting physical address of window
mov [BX].startmem,AX ; save it for later
;
; Calculate size of window in bytes to allocate memory
;
mov AX,[BX].rightcol
inc AX
sub AX,[BX].leftcol
mov [BX].xwidth,AX
mov CX,[BX].rightrow
inc CX
sub CX,[BX].leftrow
mov [BX].height,CX
mul CL ; AX = nbr of bytes of screen area
shl AX,1 ; times 2 to get attributes also
;
; Do DOS call to allocate memory
;
mov CL,4
shr AX,CL ; divide by 16 to get # paragraphs
inc AX ; handle any remainder
mov BX,AX
mov AH,48h ; 'allocate memory' DOS call
int 21h
mov Winseg,AX ; save returned segment
jnc cpynam
mov DX,OFFSET Memerr ; ERROR - display string
mov AH,9
int 21h
jmp exit ; and terminate
;
; Copy target program name
;
cpynam:
mov SI,OFFSET PSPstr + 1
mov DI,OFFSET Filename
xor CX,CX ; zero char count
fnlp:
cmp BYTE PTR [SI],' ' ; look for <SP>
jz fndn
cmp BYTE PTR [SI],00 ; or <NULL> terminator
jz fndn
movsb
inc CX ; count number of filename char's
jmp fnlp
fndn:
or CX,CX
jnz gotfn
mov DX,OFFSET Findmsg ; error if zero filename length
mov AH,9
int 21h
jmp freemem
gotfn:
xor AL,AL
stosb
mov FNsize,CX
;
; Copy command line string
; SI -> first parameter after filename
;
mov DI,OFFSET CLstr + 1
xor CX,CX ; zero char count
cllp:
cmp BYTE PTR [SI],00 ; look for <NULL> terminator
jz dncl
movsb
inc CX ; count number of cmd line char's
jmp cllp
dncl:
xor AL,AL ; store <NULL>
stosb
mov AL,CR ; and <CR>
stosb
mov CLstr,CL ; store cmd line count
;
; Build EXEC control block
;
mov SegCmd,OFFSET CLstr
mov SegCmd+2,DS
mov FCBptr1,OFFSET FCB1
mov FCBptr1+2,DS
mov FCBptr2,OFFSET FCB2
mov FCBptr2+2,DS
;
; Parse first parameter
;
mov SI,OFFSET CLstr + 1
mov DI,OFFSET FCB1
mov AL,01 ; scan past separators
mov AH,29h
int 21h
;
; Parse second parameter
;
mov DI,OFFSET FCB2
mov AL,01 ; scan past separators
mov AH,29h
int 21h
;
; Check for '.' in target program filename
;
mov DI,OFFSET Filename
mov CX,FNsize ; get program filename size
mov AL,'.'
repne scasb
jz fndext
;
; No extention found, try appending '.COM'
;
mov SI,OFFSET COMstr
mov DI,OFFSET Filename
add DI,FNsize
mov CX,4
rep movsb
;
; Try to OPEN the target program to see if it exists before we change
; the Int 21h vector and EXEC it.
;
mov AH,3dh
mov AL,00 ; access code
mov DX,OFFSET Filename
int 21h
jnc clsfile ; jump if file found
;
; OPEN with '.COM' extention failed, try appending '.EXE'
;
mov SI,OFFSET EXEstr
mov DI,OFFSET Filename
add DI,FNsize
mov CX,4
rep movsb
;
; Try to OPEN the '.EXE' version of the file
;
fndext:
mov AH,3dh
mov AL,00 ; access code
mov DX,OFFSET Filename
int 21h
jnc clsfile
mov DX,OFFSET Findmsg ; not found
mov AH,9
int 21h
jmp freemem
;
; Found the file, now close it and do EXEC function
;
clsfile:
mov BX,AX ; move file handle
mov AH,3eh
int 21h
;
; Redirect INT 21h
;
redirect:
push ES
cli
mov AX,0
mov ES,AX
mov AX,OFFSET New21
xchg AX,ES:[INT21OFF]
mov Save21,AX
mov AX,CS
xchg AX,ES:[INT21OFF+2]
mov Save21+2,AX
sti
pop ES
;
; Execute target program
;
mov DX,OFFSET Filename
mov BX,OFFSET Param_Block
mov AH,4bh
mov AL,0
mov SP,OFFSET Tstack
int 21h
jnc execdn
;
; Failed to execute target program. Display message and quit
;
mov AX,CS
mov DS,AX
mov DX,OFFSET Execmsg
mov AH,9
int 21h
;
execdn:
mov AX,CS ; restore segment registers
mov DS,AX
mov ES,AX
mov SS,AX
mov SP,OFFSET Pstack
;
; Restore INT 21h vector
;
cli
mov AX,0
mov ES,AX
mov AX,Save21
mov ES:[INT21OFF],AX
mov AX,Save21+2
mov ES:[INT21OFF+2],AX
sti
;
; Free allocated memory from window save area
;
freemem:
mov ES,Winseg
mov AH,49h
int 21h
exit:
mov AH,4ch ; terminate process
mov AL,00
int 21h ; won't return
;
; INT 21h will be redirected to here
;
New21:
push AX ; use USERS'S stack for first 2 words
push DS
;
mov AX,CS ; now switch to internal stack
mov DS,AX
mov SSsave,SS
mov SPsave,SP
mov SS,AX
mov SP,OFFSET Pstack
;
pushf
push ES
push BP
push SI
push DI
push DX
push CX
push BX
mov BP,SP ; save base pointer to display reg's
mov ES,AX
mov AL,Run_Flg
test AL,0ffh ; should we stop and display?
jnz runit
jmp norun ; no, restore registers and leave
runit:
cld ; clear direction flag for string operations
call Get_User_Regs ; recover registers left on user's stack
;
mov AL,Skip_Flg
test AL,0ffh ; skip certain functions?
jz noskip ; no, continue
mov AX,AXsave ; get USER's AX register with function code
cmp AH,Skip_Typ ; compare upper half to type to skip
jnz clrskip
jmp norun ; don't want to break on this one again
clrskip:
mov AL,00 ; skip flag was set but this is new
mov Skip_Flg,AL ; function, so break from now on
noskip:
call Open_Window
call Show_Regs
call Show_Help
call Disp_Text ; Display description string of DOS function
;
call Get_Key ; wait for a key pressed
call Disp_Key ; dispatch to key handler
call Close_Window
norun:
pop BX
pop CX
pop DX
pop DI
pop SI
pop BP
pop ES
popf
mov SP,SPsave
mov SS,SSsave
pop DS
pop AX
IFE TESTING
pushf
call CS:[DWORD PTR Save21]
ENDIF
push AX ; use USERS'S stack for first 2 words
push DS
;
mov AX,CS ; now switch to internal stack
mov DS,AX
mov SSsave,SS
mov SPsave,SP
mov SS,AX
mov SP,OFFSET Pstack
;
pushf
push ES
push BP
push SI
push DI
push DX
push CX
push BX
mov BP,SP ; save base pointer to display reg's
mov ES,AX
cld ; clear direction flag for string operations
call Get_User_Regs ; recover registers left on user's stack
xor AL,AL
xchg AL,Ret_Flg ; read value and clear flag for next time
test AL,0ffh ; is flag set to display return value?
jz nostop
;
call Open_Window
call Show_Regs
call Disp_Ret ; display return code in AX and flags
call Get_Key ; wait for a key pressed
call Close_Window
nostop:
pop BX
pop CX
pop DX
pop DI
pop SI
pop BP
pop ES
popf
mov SP,SPsave
mov SS,SSsave
pop DS
pop AX
retf 2
;
; Display return code in AX, carry and zero flags
;
Disp_Ret:
mov DX,OFFSET RCStr
mov DI,14
mov AX,AXsave
call OutWord
;
mov DX,OFFSET CFStr
mov DI,13
add DI,DX
mov AL,'0'
test FLsave,0001 ; carry flag is least significant bit
jz dcy
inc AL ; carry was set so change to '1'
dcy:
mov [DI],AL ; store it in string
add CX,0015h ; move cursor position
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
;
mov DX,OFFSET ZFStr
mov DI,12
add DI,DX
mov AL,'0'
test FLsave,0040h ; test zero flag
jz dzf
inc AL ; zero was set so change to '1'
dzf:
mov [DI],AL ; store it in string
add CX,0010h ; move cursor position
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
;
mov CX,0816h ; display some help
mov DX,OFFSET HlpStr4
mov AH,YELLOW
call WPrint
ret
RCStr db 'Return Code = XXXXH'
db 0
CFStr db 'Carry Flag = X'
db 0
ZFStr db 'Zero Flag = X'
db 0
;
; Recover registers on USER'S stack
;
Get_User_Regs:
push ES
les BX,Ssave
mov AX,ES:[BX] ; get DS
mov DSsave,AX
mov AX,ES:[BX+2] ; get AX
mov AXsave,AX
mov AX,ES:[BX+4] ; get IP
mov IPsave,AX
mov AX,ES:[BX+6] ; get CS
mov CSsave,AX
mov AX,[BP+REGFL] ; get FLAGS off local stack
mov FLsave,AX
pop ES
ret
;
; Display register names in window
;
Show_Regs:
mov BX,OFFSET W1 ; window
mov CX,0001h ; cursor position - row, col
mov DX,OFFSET RegStr1 ; message address
mov AH,YELLOW ; attribute
call WPrint
;
add CX,0100h ; go down one row
mov DX,OFFSET RegStr2
mov AH,WHITE
call WPrint
;
; Display register values
;
add CX,0100h ; down a row
mov AX,AXsave ; get user's AX
call Whexwd ; display hex word
;
push BP ; save base pointer for string display
mov DX,6 ; number of registers to show this loop
disreg:
add CX,0005h ; move to next register field
mov AX,[BP]
call Whexwd ; display hex word
add BP,2
dec DX
jnz disreg
;
add CX,0005h ; move to next register field
mov AX,SPsave ; display SP
add AX,4 ; add for 2 pushes we did
call Whexwd
;
add CX,0005h ; move to next register field
mov AX,DSsave ; display DS
call Whexwd
;
add CX,0005h ; display ES
mov AX,[BP]
call Whexwd
;
add CX,0005h
mov AX,SSsave ; display SS
call Whexwd
;
add CX,0005h
mov AX,CSsave ; display CS
call Whexwd
;
add CX,0005h
mov AX,IPsave ; display IP
call Whexwd
;
add CX,0005h
mov AX,FLsave ; display FLAGS
call Whexwd
pop BP ; restore base pointer so display routines
; can use it
ret
;
; Display HELP in Window
;
Show_Help:
mov CX,0801h ; cursor position - row, col
mov AH,LTRED ; attribute for char
mov AL,'S'
call WChar ; write one character with attribute
;
add CX,0001h ; add 1 to column number
mov DX,OFFSET HlpStr1 ; message address
mov AH,WHITE
call WPrint
;
add CX,0017h ; move column number
mov AH,LTRED ; attribute for char
mov AL,'R'
call WChar ; write one character with attribute
;
add CX,0001h ; move column number
mov DX,OFFSET HlpStr2
mov AH,WHITE
call WPrint
;
add CX,000dh
mov AH,LTRED
mov AL,'E'
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,'S'
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,'C'
call WChar
;
add CX,0001h
mov DX,OFFSET HlpStr3
mov AH,WHITE
call WPrint
ret
;
; HextoDec converts a word in AX to an ASCII string
; Entry:
; AX = word to convert
; Exit:
; SI = Pointer to last two character of ASCII string in 'Astr'
;
HextoDec:
push AX
push CX
push DX
push DI
;
mov DI,OFFSET Astr
mov CX,10000
xor DX,DX
div CX ; num / 10000
add AL,'0'
stosb
mov AX,DX
mov CX,1000
xor DX,DX
div CX ; num / 1000
add AL,'0'
stosb
mov AX,DX
mov CX,100
xor DX,DX
div CX ; num / 100
add AL,'0'
stosb
mov AX,DX
mov CX,10
xor DX,DX
div CX ; num / 10
add AL,'0'
stosb
mov AX,DX
add AL,'0'
stosb
xor AL,AL ; <NULL> terminator in string
stosb
sub DI,3 ; back up pointer
mov SI,DI
;
pop DI
pop DX
pop CX
pop AX
ret
;
; Display the text description of the current DOS function code
;
Disp_Text:
mov AX,AXsave ; get user's function code
cmp AH,63h ; is it in range?
jnb not_fnd ; jump if no
mov DI,OFFSET FCtbl
mov CX,LENFC / 6 ; number of entries
cmpdt:
cmp AH,[DI+1] ; is this the right function?
jz dtexec
add DI,6 ; no, point to next
loop cmpdt
not_fnd:
mov DX,OFFSET STRUN
call Disp_Str
ret
dtexec:
mov DX,[DI+2] ; get pointer to string
call [WORD PTR DI+4] ; go to display routine
ret
;
; Display string of DOS function code description
;
; Entry:
; DX = pointer to string
;
Disp_Str:
mov CX,0501h
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
ret
;
; Only one string must be inserted.
; It is pointed to by user's DS:DX.
; Entry:
; DX = text string containing description of function call
; DI = offset within local string (DX) to put user's (DS:DX)
; CX = max length before you will hit right side of Window
;
One_String:
add DI,DX
push DS
mov DS,DSsave
mov SI,[BP+REGDX] ; get USER's DS:DX value
rep movsb ; copy user's memory to text string
pop DS
call Disp_Str
ret
;
; Convert users's DS and DX to ASCII, imbed them in target string
; Entry:
; DX = pointer to string
; DI = offset where to put converted DS:DX
;
OutDSDX:
add DI,DX
mov AX,DSsave ; get user's DS
call Shexwrd
inc DI ; skip past ':'
mov AX,[BP+REGDX] ; get user's DX
call Shexwrd
call Disp_Str
ret
;
; Convert word in AX to ASCII, imbed it in target string
; Entry:
; AX = word to convert
; DX = pointer to string
; DI = offset where to put converted AX
;
OutWord:
add DI,DX
call Shexwrd
call Disp_Str
ret
;
; Convert 'AL' to ASCII and imbed it in target string
; Entry:
; DX = target string
; DI = offset to put converted 'AL'
; AL = value to convert
;
OutByte:
add DI,DX
call Shexbyt
call Disp_Str
ret
;
; Routines to build string for display - some values need to be filled in
;
; Entry:
; DX = pointer to string
;
Disp_02:
Disp_04:
Disp_05:
mov DI,DX
add DI,22 ; offset this many into string
mov AX,[BP+REGDX] ; DL register has char to output
call Shexbyt ; convert it to ASCII
mov [DI+8],AL ; show hex byte
call Disp_Str
ret
;
; Direct Keyboard/Display I/O
;
Disp_06:
call Disp_Str
mov AX,[BP+REGDX] ; DL register has I/O type
mov DX,OFFSET STR06I
cmp AL,0ffh ; input character?
jz d06io
mov DX,OFFSET STR02 ; no, output character in 'DL'
mov DI,DX
add DI,22 ; offset this many into string
call Shexbyt ; convert it to ASCII
mov [DI+8],AL ; show hex byte
d06io:
add CX,0015h
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
ret
;
; Display String
; Entry:
; DX = pointer to string
;
Disp_09:
Disp_39:
Disp_3a:
Disp_3b:
Disp_3c:
Disp_3d:
Disp_41:
Disp_5a:
Disp_5b:
mov DI,18 ; offset where (DS:DX) goes within string
mov cx,52 ; max number of char's to fit in window
call One_String
ret
Disp_0a:
Disp_23:
mov DI,27
call OutDSDX
ret
;
; Clear Keyboard and Do Function
;
Disp_0c:
mov DI,31
mov AX,AXsave ; AL register has function number
call OutByte
ret
;
; Select Disk
;
Disp_0e:
mov DI,12
mov AX,[BP+REGDX] ; DL register has char to output
call OutByte
ret
;
; Open File Using FCB
;
Disp_0f:
mov DI,23
call OutDSDX
ret
;
; Close File Using FCB
;
Disp_10:
mov DI,24
call OutDSDX
ret
;
; Search For First Matching File Using FCB
;
Disp_11:
mov DI,44
call OutDSDX
ret
;
; Search For Next Matching File Using FCB
;
Disp_12:
mov DI,43
call OutDSDX
ret
;
; Delete File Using FCB
; Create File Using FCB
; Rename File Using FCB
;
Disp_13:
Disp_16:
Disp_17:
mov DI,25
call OutDSDX
ret
;
; Read Sequential File Record Using FCB
;
Disp_14:
mov DI,41
call OutDSDX
ret
;
; Write Sequential File Record Using FCB
;
Disp_15:
mov DI,42
call OutDSDX
ret
;
; Set Disk Transfer Address
;
Disp_1a:
mov DI,29
call OutDSDX
ret
;
; Get FAT Information For Drive
;
Disp_1c:
mov DI,30
mov AX,[BP+REGDX] ; DL register has drive number
call OutByte
ret
;
; Read Random File Record Using FCB
; Set Random Record Field Using FCB
;
Disp_21:
Disp_24:
mov DI,37
call OutDSDX
ret
;
; Write Random File Record Using FCB
;
Disp_22:
mov DI,38
call OutDSDX
ret
;
; Set Interrupt Vector
;
Disp_25:
mov DI,DX
add DI,21
mov AX,AXsave ; AL has interrupt vector number
call Shexbyt
mov DI,28
call OutDSDX
ret
;
; Create New Program Segment
;
Disp_26:
mov DI,38
mov AX,[BP+REGDX] ; get user's DX
call OutWord
ret
;
; Read Random File Records
;
Disp_27:
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX register has record count
call Shexwrd
mov DI,44
call OutDSDX
ret
;
; Write Random File Records
;
Disp_28:
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX register has record count
call Shexwrd
mov DI,45
call OutDSDX
ret
;
; Parse Filename
;
Disp_29:
mov DI,18 ; offset where (DS:SI) goes within string
mov cx,52 ; max number of char's to fit in window
add DI,DX
push DI ; save for scan later
push DS
mov DS,DSsave
mov SI,[BP+REGSI] ; get USER's DS:SI value
rep movsb ; copy user's memory to text string
pop DS
;
; look for <CR> in string and put <NULL> terminator there
;
pop DI
mov AL,CR
mov cx,52
repne scasb
jnz dpf
dec DI
xor AL,AL
mov [DI],AL
dpf:
call Disp_Str
ret
;
; Set Date
;
Disp_2b:
mov DI,DX
add DI,22
mov AX,[BP+REGDX] ; DX register has month/day
mov AL,AH
xor AH,AH
call HextoDec ; convert month
movsb
movsb
inc DI ; skip past '/'
mov AX,[BP+REGDX]
xor AH,AH
call HextoDec ; convert day
movsb
movsb
inc DI ; skip past '/'
mov AX,[BP+REGCX]
call HextoDec ; convert year
movsb
movsb
call Disp_Str
ret
;
; Set Time
;
Disp_2d:
mov DI,DX
add DI,33
mov AX,[BP+REGCX] ; CX register has hours/minutes
mov AL,AH
xor AH,AH
call HextoDec ; convert hours
movsb
movsb
inc DI ; skip past ':'
mov AX,[BP+REGCX]
xor AH,AH
call HextoDec ; convert minutes
movsb
movsb
inc DI ; skip past ':'
mov AX,[BP+REGDX] ; DX has seconds/hundreds of seconds
mov AL,AH
xor AH,AH
call HextoDec ; convert seconds
movsb
movsb
inc DI ; skip past ':'
mov AX,[BP+REGDX]
xor AH,AH
call HextoDec ; convert hundreds
movsb
movsb
call Disp_Str
ret
;
; Set Disk Write Verification
;
Disp_2e:
mov DI,DX
add DI,28
mov AX,AXsave ; AL register has verify switch
mov SI,OFFSET OFFstr
cmp AL,00 ; AL = 0 means OFF
jz verptr
mov SI,OFFSET ONstr
cmp AL,01 ; AL = 1 means ON
jz verptr
mov SI,OFFSET Blanks3 ; unknown code
verptr:
mov CX,3
rep movsb
call Disp_Str
ret
;
; Get/Set Control-Break Status
;
Disp_33:
mov AX,AXsave ; AL register has get/set switch
cmp AL,01 ; AL = 1 for SET
jz setcbs
cmp AL,00 ; AL = 0 for GET
jnz unk33 ; jump if unknown code
mov DX,OFFSET STR33G
unk33:
call Disp_Str
ret
setcbs:
mov DX,OFFSET STR33S ; point to 'SET' string
mov DI,DX
add DI,25
mov AX,[BP+REGDX] ; DL has set code
mov SI,OFFSET OFFstr
cmp AL,00 ; AL = 00 means OFF
jz gscbs
mov SI,OFFSET ONstr
cmp AL,01 ; AL = 01 means ON
jz gscbs
mov SI,OFFSET Blanks3
gscbs:
mov CX,3
rep movsb
call Disp_Str
ret
;
; Get Interrupt Vector
;
Disp_35:
mov DI,21
mov AX,AXsave ; AL has interrupt vector number
call OutByte
ret
;
; Get Disk Free Space On Drive
;
Disp_36:
mov DI,29
mov AX,[BP+REGDX] ; DL register has drive code
call OutByte
ret
;
; Close File Handle
;
Disp_3e:
mov DI,18
mov AX,[BP+REGBX] ; BX register has file handle
call OutWord
ret
;
; Duplicate File Handle
;
Disp_45:
mov DI,22
mov AX,[BP+REGBX] ; BX register has file handle
call OutWord
ret
;
; Read From File or Device
;
Disp_3f:
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX has number of bytes to read
call Shexwrd
mov DI,37
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
; Write To File or Device
;
Disp_40:
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX has number of bytes to read
call Shexwrd
mov DI,36
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
; Move File Pointer
;
Disp_42:
mov DI,DX
add DI,17
mov AX,[BP+REGBX] ; BX register has file handle
call Shexwrd
add DI,13
mov AX,[BP+REGCX] ; CX has upper half of offset
call Shexwrd
inc DI ; skip past ':'
mov AX,[BP+REGDX] ; CX has lower half of offset
call Shexwrd
add DI,7
mov AX,AXsave ; AL has method code
mov SI,OFFSET BOFstr
cmp AL,00 ; beginning of file?
jz mvptr
mov SI,OFFSET CURstr
cmp AL,01 ; current location?
jz mvptr
mov SI,OFFSET EOFstr
cmp AL,02 ; end of file?
jz mvptr
mov SI,OFFSET Blanks17 ; unknown
mvptr:
mov cx,17 ; string length
rep movsb
call Disp_Str
ret
;
; Get/Set file attributes
;
Disp_43:
mov AX,AXsave ; user's AX has get/set flag
cmp AL,00 ; 'get' code?
jz fgptr
cmp AL,01 ; 'set' code?
jz fsptr
call Disp_Str ; unknown code
ret
fgptr:
mov DX,OFFSET STR43G ; point to GET string
jmp SHORT faptr
;
fsptr:
mov DX,OFFSET STR43S ; point to SET string
faptr:
mov DI,18
mov cx,52 ; max number of char's to fit in window
call One_String
ret
;
; I/O Control For Devices
;
Disp_44:
mov AX,AXsave
cmp AL,00
jz jd440
cmp AL,01
jz jd441
cmp AL,02
jz jd442
cmp AL,03
jz jd443
cmp AL,04
jz jd444
cmp AL,05
jz jd445
cmp AL,06
jz jd446
cmp AL,07
jz jd447
cmp AL,08
jz jd448
cmp AL,11
jz jd4411
call Disp_Str ; unknown code
ret
jd440: jmp d440
jd441: jmp d441
jd442: jmp d442
jd443: jmp d443
jd444: jmp d444
jd445: jmp d445
jd446: jmp d446
jd447: jmp d447
jd448: jmp d448
jd4411: jmp d4411
d440:
mov DX,OFFSET STR440 ; Get Info For Device
mov DI,20
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d441:
mov DX,OFFSET STR441 ; Set Info For Device
mov DI,DX
add DI,20
mov AX,[BP+REGBX] ; BX has file handle
call Shexwrd
mov DI,29
mov AX,[BP+REGDX] ; DX has device information
call OutWord
ret
;
d442:
mov DX,OFFSET STR442 ; Read From Drive Control Channel
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,52
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d443:
mov DX,OFFSET STR443 ; Write To Drive Control Channel
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,51
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d444:
mov DX,OFFSET STR444 ; Read From Control Channel of Drive
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,47
mov AX,[BP+REGBX] ; BL has drive
call OutByte
ret
;
d445:
mov DX,OFFSET STR445 ; Write To Control Channel of Drive
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,46
mov AX,[BP+REGBX] ; BL has drive
call OutByte
ret
;
d446:
mov DX,OFFSET STR446 ; Get Input Status of Device
mov DI,27
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d447:
mov DX,OFFSET STR447 ; Get Output Status of Device
mov DI,28
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d448:
mov DX,OFFSET STR448 ; Report Whether Device Has Removable Media
mov DI,22
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d4411:
mov DX,OFFSET STR4411 ; Set Retries For Device
mov DI,DX
add DI,23
mov AX,[BP+REGBX] ; BX has file handle
call Shexwrd
add DI,5
mov AX,[BP+REGDX] ; DX has retry count
call Shexwrd
mov DI,55
mov AX,[BP+REGCX] ; CX has interval between tries
call OutWord
ret
;
; Force Duplication of Handle
;
Disp_46:
mov DI,DX
add DI,28
mov AX,[BP+REGBX] ; BX has the existing file handle
call Shexwrd
mov DI,37
mov AX,[BP+REGCX] ; CX has the second file handle
call OutWord
ret
;
; Get Current Directory
;
Disp_47:
mov DI,DX
add DI,31
mov AX,[BP+REGDX] ; DL register has drive code
call Shexbyt
add DI,7
mov AX,DSsave
call Shexwrd
inc DI ; skip ':'
mov AX,[BP+REGSI] ; get USER's DS:SI value
call Shexwrd
call Disp_Str
ret
;
; Allocate Memory
;
Disp_48:
mov DI,9
mov AX,[BP+REGBX] ; BX has the memory requested in paragraphs
call OutWord
ret
;
; Free Allocated Memory
;
Disp_49:
mov DI,33
mov AX,[BP+REGES] ; ES has the segment address
call OutWord
ret
;
; Modify Memory Block
;
Disp_4a:
mov DI,DX
add DI,31
mov AX,[BP+REGES] ; ES has the segment address
call Shexwrd
mov DI,43
mov AX,[BP+REGBX] ; BX has size in paragraphs
call OutWord
ret
;
; Load or Exececute Program
; Find First Matching File
;
Disp_4b:
Disp_4e:
mov DI,29 ; offset where (DS:DX) goes within string
mov cx,41 ; max number of char's to fit in window
call One_String
ret
;
; Terminate Process with Return Code
;
Disp_4c:
mov DI,35
mov AX,Axsave ; AL register return code
call OutByte
ret
;
; Rename File
;
Disp_56:
mov DI,29
mov cx,41
call One_String ; display 'old' name
;
mov DX,OFFSET STR56N
mov DI,DX
add DI,29
push DS
mov DS,[BP+REGES]
mov SI,[BP+REGDI] ; get USER's ES:DI value
mov cx,41 ; to display 'new' name
rep movsb
pop DS
mov CX,0601h
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
ret
;
; Get Date and Time of File
;
Disp_57:
mov AX,AXsave ; user's AL has get/set indicator
cmp AL,00 ; is it GET?
jz gdtptr
cmp AL,01 ; is it SET?
jz sdtptr
mov DI,37 ; unknown function
mov AX,[BP+REGBX] ; file handle
call OutWord
ret
gdtptr:
mov DX,OFFSET STR57G
jmp SHORT ddtptr
;
sdtptr:
mov DX,OFFSET STR57S
ddtptr:
mov DI,33
mov AX,[BP+REGBX] ; BX register has file handle
call OutWord
ret
;
; Lock/Unlock File
;
Disp_5c:
mov AX,AXsave
cmp AL,00 ; 0 = Lock
jz dlck
cmp AL,01 ; 1 = Unlock
jz dunlck
mov DI,17
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
dlck:
mov DX,OFFSET STR5c0
mov DI,10
mov AX,[BP+REGBX]
call OutWord
ret
;
dunlck:
mov DX,OFFSET STR5c1
mov DI,12
mov AX,[BP+REGBX]
call OutWord
ret
;
; Table of function codes.
; (1st) word is DOS function code (AH),
; (2nd) word is pointer to string to display,
; (3rd) word is subroutine address to handle display of this type function.
;
FCtbl:
dw 0000h, STR00, Disp_Str
dw 0100h, STR01, Disp_Str
dw 0200h, STR02, Disp_02
dw 0300h, STR03, Disp_Str
dw 0400h, STR04, Disp_04
dw 0500h, STR05, Disp_05
dw 0600h, STR06, Disp_06
dw 0700h, STR07, Disp_Str
dw 0800h, STR08, Disp_Str
dw 0900h, STR09, Disp_09
dw 0a00h, STR0a, Disp_0a
dw 0b00h, STR0b, Disp_Str
dw 0c00h, STR0c, Disp_0c
dw 0d00h, STR0d, Disp_Str
dw 0e00h, STR0e, Disp_0e
dw 0f00h, STR0f, Disp_0f
dw 1000h, STR10, Disp_10
dw 1100h, STR11, Disp_11
dw 1200h, STR12, Disp_12
dw 1300h, STR13, Disp_13
dw 1400h, STR14, Disp_14
dw 1500h, STR15, Disp_15
dw 1600h, STR16, Disp_16
dw 1700h, STR17, Disp_17
dw 1800h, STRUN, Disp_Str
dw 1900h, STR19, Disp_Str
dw 1a00h, STR1a, Disp_1a
dw 1b00h, STR1b, Disp_Str
dw 1c00h, STR1c, Disp_1c
dw 1d00h, STRUN, Disp_Str
dw 1e00h, STRUN, Disp_Str
dw 1f00h, STRUN, Disp_Str
dw 2000h, STRUN, Disp_Str
dw 2100h, STR21, Disp_21
dw 2200h, STR22, Disp_22
dw 2300h, STR23, Disp_23
dw 2400h, STR24, Disp_24
dw 2500h, STR25, Disp_25
dw 2600h, STR26, Disp_26
dw 2700h, STR27, Disp_27
dw 2800h, STR28, Disp_28
dw 2900h, STR29, Disp_29
dw 2a00h, STR2a, Disp_Str
dw 2b00h, STR2b, Disp_2b
dw 2c00h, STR2c, Disp_Str
dw 2d00h, STR2d, Disp_2d
dw 2e00h, STR2e, Disp_2e
dw 2f00h, STR2f, Disp_Str
dw 3000h, STR30, Disp_Str
dw 3100h, STR31, Disp_Str
dw 3200h, STRUN, Disp_Str
dw 3300h, STR33, Disp_33
dw 3400h, STRUN, Disp_Str
dw 3500h, STR35, Disp_35
dw 3600h, STR36, Disp_36
dw 3700h, STR37, Disp_Str
dw 3800h, STR38, Disp_Str
dw 3900h, STR39, Disp_39
dw 3a00h, STR3a, Disp_3a
dw 3b00h, STR3b, Disp_3b
dw 3c00h, STR3c, Disp_3c
dw 3d00h, STR3d, Disp_3d
dw 3e00h, STR3e, Disp_3e
dw 3f00h, STR3f, Disp_3f
dw 4000h, STR40, Disp_40
dw 4100h, STR41, Disp_41
dw 4200h, STR42, Disp_42
dw 4300h, STR43, Disp_43
dw 4400h, STR44, Disp_44
dw 4500h, STR45, Disp_45
dw 4600h, STR46, Disp_46
dw 4700h, STR47, Disp_47
dw 4800h, STR48, Disp_48
dw 4900h, STR49, Disp_49
dw 4a00h, STR4a, Disp_4a
dw 4b00h, STR4b, Disp_4b
dw 4c00h, STR4c, Disp_4c
dw 4d00h, STR4d, Disp_Str
dw 4e00h, STR4e, Disp_4e
dw 4f00h, STR4f, Disp_Str
dw 5000h, STRUN, Disp_Str
dw 5100h, STRUN, Disp_Str
dw 5200h, STRUN, Disp_Str
dw 5300h, STRUN, Disp_Str
dw 5400h, STR54, Disp_Str
dw 5500h, STRUN, Disp_Str
dw 5600h, STR56, Disp_56
dw 5700h, STR57, Disp_57
dw 5800h, STRUN, Disp_Str
dw 5900h, STR59, Disp_Str
dw 5a00h, STR5a, Disp_5a
dw 5b00h, STR5b, Disp_5b
dw 5c00h, STR5c, Disp_5c
dw 5d00h, STRUN, Disp_Str
dw 5e00h, STRUN, Disp_Str
dw 5f00h, STRUN, Disp_Str
dw 6000h, STRUN, Disp_Str
dw 6100h, STRUN, Disp_Str
dw 6200h, STR62, Disp_Str
LENFC EQU $ - FCtbl
;
; The XX's are just place holders for help in alignment during debugging
;
STR00 db 'Terminate Program'
db 0
STR01 db 'Keyboard Input With Echo'
db 0
STR02 db 'Output Character Hex XX ASCII X'
db 0
STR03 db 'Serial Input'
db 0
STR04 db 'Serial Output Hex XX ASCII X'
db 0
STR05 db 'Printer Output Hex XX ASCII X'
db 0
STR06 db 'Direct Console I/O - '
db 0
STR06I db 'Input Character'
db 0
STR07 db 'Direct Console Input Without Echo'
db 0
STR08 db 'Console Input Without Echo'
db 0
STR09 db 'Display String -->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR0a db 'Buffered Keyboard Input To XXXX:XXXXH'
db 0
STR0b db 'Check Standard Input Status'
db 0
STR0c db 'Clear Keyboard and Do Function XXH'
db 0
STR0d db 'Reset Disk'
db 0
STR0e db 'Select Disk XXH'
db 0
STR0f db 'Open File Using FCB at XXXX:XXXXH'
db 0
STR10 db 'Close File Using FCB at XXXX:XXXXH'
db 0
STR11 db 'Search For First Matching File Using FCB at XXXX:XXXXH'
db 0
STR12 db 'Search For Next Matching File Using FCB at XXXX:XXXXH'
db 0
STR13 db 'Delete File Using FCB at XXXX:XXXXH'
db 0
STR14 db 'Read Sequential File Record Using FCB at XXXX:XXXXH'
db 0
STR15 db 'Write Sequential File Record Using FCB at XXXX:XXXXH'
db 0
STR16 db 'Create File Using FCB at XXXX:XXXXH'
db 0
STR17 db 'Rename File Using FCB at XXXX:XXXXH'
db 0
STR19 db 'Report Current Drive'
db 0
STR1a db 'Set Disk Transfer Address To XXXX:XXXXH'
db 0
STR1b db 'Get FAT Information For Default Drive'
db 0
STR1c db 'Get FAT Information For Drive XXH'
db 0
STR21 db 'Read Random File Record Using FCB at XXXX:XXXXH'
db 0
STR22 db 'Write Random File Record Using FCB at XXXX:XXXXH'
db 0
STR23 db 'Get File Size Using FCB at XXXX:XXXXH'
db 0
STR24 db 'Set Random Record Field Using FCB at XXXX:XXXXH'
db 0
STR25 db 'Set Interrupt Vector XXH to XXXX:XXXXH'
db 0
STR26 db 'Create New Program Segment At Segment XXXXH'
db 0
STR27 db 'Read XXXXH Random File Records Using FCB at XXXX:XXXXH'
db 0
STR28 db 'Write XXXXH Random File Records Using FCB at XXXX:XXXXH'
db 0
STR29 db 'Parse Filename -->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR2a db 'Get Date'
db 0
STR2b db 'Set Date To mm/dd/yy XX/XX/XX'
db 0
STR2c db 'Get Time'
db 0
STR2d db 'Set Time To Hrs:Mins:Secs:Hunds XX:XX:XX:XX'
db 0
STR2e db 'Set Disk Write Verification XXX'
db 0
STR2f db 'Get Disk Transfer Address'
db 0
STR30 db 'Get DOS Version Number'
db 0
STR31 db 'Terminate Process and Remain Resident'
db 0
STR33 db 'Get/Set Control-Break Status'
db 0
STR33G db 'Get Control-Break Status'
db 0
STR33S db 'Set Control-Break Status XXX'
db 0
STR35 db 'Get Interrupt Vector XXH'
db 0
STR36 db 'Get Disk Free Space On Drive XXH'
db 0
STR37 db 'Get DOS Switch Character'
db 0
STR38 db 'Get/Set Country Dependent Information'
db 0
STR39 db 'Create Subdir --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3a db 'Remove Subdir --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3b db 'Change Dir To --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3c db 'Create File ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3d db 'Open File ------->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3e db 'Close File Handle XXXXH'
db 0
STR3f db 'Read XXXXH Bytes From File or Device XXXXH'
db 0
STR40 db 'Write XXXXH Bytes To File or Device XXXXH'
db 0
STR41 db 'Delete File ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR42 db 'Move File Handle XXXXH Pointer By XXXX:XXXXH From '
db 'XXXXXXXXXXXXXXXXX'
db 0
STR43 db 'Get/Set File Attributes'
db 0
STR43G db 'Get File Attrib ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR43S db 'Set File Attrib ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR44 db 'I/O Control For Devices'
db 0
STR440 db 'Get Info For Device XXXXH'
db 0
STR441 db 'Set Info For Device XXXXH to XXXXH'
db 0
STR442 db 'Read XXXXH Bytes From Drive Control Channel of File XXXXH'
db 0
STR443 db 'Write XXXXH Bytes To Drive Control Channel of File XXXXH'
db 0
STR444 db 'Read XXXXH Bytes From Control Channel of Drive XXH'
db 0
STR445 db 'Write XXXXH Bytes To Control Channel of Drive XXH'
db 0
STR446 db 'Get Input Status of Device XXXXH'
db 0
STR447 db 'Get Output Status of Device XXXXH'
db 0
STR448 db 'Report Whether Device XXXXH Has Removable Media'
db 0
STR4411 db 'Set Retries For Device XXXXH to XXXXH With Interval of XXXXH'
db 0
STR45 db 'Duplicate File Handle XXXXH'
db 0
STR46 db 'Force Duplication of Handle XXXXH to XXXXH'
db 0
STR47 db 'Get Current Directory of Drive XXH into XXXX:XXXXH'
db 0
STR48 db 'Allocate XXXXH Paragraphs of Memory'
db 0
STR49 db 'Free Allocated Memory at Segment XXXXH'
db 0
STR4a db 'Modify Memory Block at Segment XXXXH to be XXXXH Paragraphs'
db 0
STR4b db 'Load or Execute Program ---->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR4c db 'Terminate Process With Return Code XXH'
db 0
STR4d db 'Get Return Code of Subprocess'
db 0
STR4e db 'Find First Matching File --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR4f db 'Find Next Matching File'
db 0
STR54 db 'Get Verify State'
db 0
STR56 db 'Rename File Old Name ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR56N db ' New Name ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR57 db 'Get/Set Date and Time of File Handle XXXXH'
db 0
STR57G db 'Get Date and Time of File Handle XXXXH'
db 0
STR57S db 'Set Date and Time of File Handle XXXXH'
db 0
STR59 db 'Get Extended Error Code'
db 0
STR5a db 'Create Temp File XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR5b db 'Create New File XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR5c db 'Lock/Unlock File XXXXH'
db 0
STR5c0 db 'Lock File XXXXH'
db 0
STR5c1 db 'Unlock File XXXXH'
db 0
STR62 db 'Get PSP Address'
db 0
STRUN db '** Undocumented Function Code **'
db 0
;
; Don't change the size of the following strings
;
Blanks3 db ' '
Blanks17 db ' '
ONstr db 'ON '
OFFstr db 'OFF'
BOFstr db 'Beginning of File'
CURstr db 'Current Location '
EOFstr db 'End of File '
Open_Window:
push ES
mov BX,OFFSET W1 ; window parameters
;
; Save current contents of window area
;
mov SI,[BX].startmem ; screen addr of start of window
mov DX,[BX].height
mov ES,Winseg ; point to allocated memory block
mov DI,0000
saverow:
push DS
mov CX,[BX].xwidth
mov DS,Scrseg ; get screen segment
push SI ; save screen offset
rep movsw ; do word to get char and attribute
pop SI
pop DS
add SI,BytesPL ; next row down
dec DX
jnz saverow
;
; Draw window
;
mov ES,Scrseg ; get screen segment
mov DI,[BX].startmem ; physical addr of start of window
mov AH,HIWHITE
;
; Draw top border
;
push DI
mov AL,ULC ; write upper left corner
stosw
mov CX,[BX].xwidth
sub CX,2
mov AL,BRDROW
rep stosw
mov AL,URC ; write upper right corner
stosw
pop DI
add DI,BytesPL ; next row down
;
; Draw middle of window
;
mov DX,[BX].height
sub DX,2
winrows:
push DI
mov AL,BRDCOL ; left border column
stosw
mov CX,[BX].xwidth
sub CX,2
mov AL,BLANK
rep stosw
mov AL,BRDCOL ; right border column
stosw
pop DI
add DI,BytesPL ; next row down
dec DX
jnz winrows
;
; Draw bottom border
;
push DI
mov AL,LLC ; write lower left corner
stosw
mov CX,[BX].xwidth
sub CX,2
mov AL,BRDROW
rep stosw
mov AL,LRC ; write lower right corner
stosw
pop DI
pop ES
ret
Close_Window:
mov BX,OFFSET W1
mov DI,[BX].startmem ; physical addr of screen area
mov ES,Scrseg ; point to allocated memory block
mov SI,0000 ; start of save memory block
mov DX,[BX].height
resrow:
push DS
mov CX,[BX].xwidth
mov DS,Winseg ; get saved memory segment
push DI ; save screen offset
rep movsw ; do word to get char and attribute
pop DI
pop DS
add DI,BytesPL ; next row down
dec DX
jnz resrow
ret
;
; Print a string in window.
; Entry:
; CX = Row, Col position relative to start of window
; BX = Window pointer
; AH = Attribute
; DX = addr of string
;
WPrint:
push ES
call GetRC ; convert to row, col in DI
mov ES,Scrseg
mov SI,DX ; move string address
wpwrt:
cmp BYTE PTR [SI],00 ; test for string terminator <NULL>
jz wpexit
lodsb
stosw
jmp wpwrt
wpexit:
pop ES
ret
;
; Write one character and attribute to window
;
; Entry:
; CX = Row, Col position relative to start of window
; BX = Window pointer
; AH = attr
; AL = char
;
WChar:
push ES
call GetRC ; convert to row, col in DI
mov ES,Scrseg
stosw
pop ES
ret
;
; Convert row, col in CX to physical addr in DI
;
GetRC:
push AX
push DX
mov DI,[BX].startmem ; physical start of window memory
add DI,BytesPL ; go down a row
add DI,2 ; go in one char, this is 0,0
mov AL,CH
xor AH,AH ; AX = relative row number
mul BytesPL ; this clobbers DX
add DI,AX
mov AX,CX ; restore coordinates
xor AH,AH ; AX = relative col number
shl AX,1 ; times 2 for attribute
add DI,AX
pop DX
pop AX
ret
;
; WRITE HEX WORD
; Convert a hex word to an ASCII string and display it
; Entry:
; CX = Row, Col position relative to start of window
; BX = Window pointer
; AX = Word to convert
;
Whexwd:
push AX
push BX
push CX
push DX
;
push BX ; save window pointer
push CX ; and row, col
mov DI,OFFSET Astr
xchg AH,AL
call Shexbyt
xchg AH,AL
call Shexbyt
xor AL,AL
stosb ; make sure of terminating NULL
mov DX,OFFSET Astr
pop CX ; get row, col
pop BX ; and Window ptr
mov AH,HIWHITE ; set attribute
call WPrint
;
pop DX
pop CX
pop BX
pop AX
ret
;
; STORE HEX WORD
; Convert a hex word to ASCII and store it in destination string
; Entry:
; AX = Word to convert
; DI = destination pointer
;
Shexwrd:
xchg AL,AH ; convert upper half first
call Shexbyt
xchg AL,AH ; convert lower half
call Shexbyt
ret
;
; STORE HEX BYTE
; Convert a hex byte to ASCII and store it in destination string
; Entry:
; AL = Byte to convert
; DI = destination pointer
;
Shexbyt:
push AX
mov AH,AL ; save temporarily
shr AL,1
shr AL,1
shr AL,1
shr AL,1
cmp AL,10
jb wh1
add AL,07
wh1:
add AL,'0'
stosb
mov AL,AH
and AL,0fh
cmp AL,10
jb wh2
add AL,07
wh2:
add AL,'0'
stosb
pop AX
ret
;
; Check if key pressed requires special handling
;
; Entry:
; AX = key pressed
;
Disp_Key:
mov DI,OFFSET Keytbl ; keys and subroutine addresses
mov CX,LENKTAB / 4 ; number of entries
cmpdk:
cmp AX,[DI] ; is key in table?
jz dkexec
add DI,4 ; no, point to next key value
loop cmpdk
ret
dkexec:
add DI,2
call [WORD PTR DI]
ret
;
; Table of keys to watch for followed by the address of the routine to execute
;
Keytbl dw ESCAPE, DO_Esc
dw BIGS, Do_Skey
dw SMALLS, Do_Skey
dw BIGR, Do_Rkey
dw SMALLR, Do_Rkey
LENKTAB EQU $ - Keytbl
;
; If ESC key, clear 'running flag' so Int 21h will not be stopped each time
;
Do_Esc:
mov AL,00
mov Run_Flg,AL
ret
;
; 'S' key - skip successive functions of current type.
; Return to intercepting calls when something new comes along.
; This is so you don't have to sit through dozens if Function '2' calls
; while the target program outputs a string to the display.
;
Do_Skey:
mov AL,0ffh
mov Skip_Flg,AL ; set flag to show we should skip something
mov AX,AXsave ; get current function code
mov Skip_Typ,AH ; save it
ret
;
; 'R' key - stop after INT 21h call and let user see result registers
;
Do_Rkey:
mov AL,0ffh
mov Ret_Flg,AL ; set flag
ret
;
; Wait for any key pressed
;
Get_Key:
mov AH,00
int 16h
ret
XTest:
mov AH,02 ; write char
mov DL,07 ; <BELL>
int 21h
iret
;
; Define format of WINDOW structure
;
Window STRUC
leftrow dw ?
leftcol dw ?
rightrow dw ?
rightcol dw ?
xwidth dw ?
height dw ?
startmem dw ?
Window ENDS
;
; Allocate and intialize WINDOW parameters
;
W1 Window <8, 2, 18, 74, 0, 0, 0>
Winseg dw 0000 ; store segment of allocated memory
; for saving screen data
Scrseg dw 0b800h ; segment where screen memory can be found
BytesPL dw 80*2 ; number of bytes per line (char + attr)
Run_Flg db 0ffh ; 'running' flag
Ret_Flg db 00 ; 'stop on return' flag
;
; The following two variables are initialized the way they are to skip
; the first Int 21 call generated by 'STEPDOS' to EXEC the target program.
;
Skip_Typ db 4bh ; type of function call to skip temporarily
Skip_Flg db 0ffh ; set if function should be skipped
Save21 dw ? ; save original Int21 vector here, IP
dw ? ; and SEG
Ssave LABEL DWORD
SPsave dw ? ; save some of the user's registers here
SSsave dw ? ; others will be on local stack
AXsave dw ? ; these will have been left on user's
DSsave dw ? ; stack instead of local stack
CSsave dw ?
IPsave dw ?
FLsave dw ?
;
; Parameter block that will be passed to the EXEC function call (4bh) of DOS
;
Param_Block LABEL WORD
SegEnv dw ? ; segment addr of environment string
SegCmd dw ? ; segmented ptr to command line
dw ?
FCBptr1 dw ? ; segmented ptr to first FCB
dw ?
FCBptr2 dw ? ; segmented ptr to second FCB
dw ?
;
; File name that will be passed to the EXEC function call of DOS
;
Filename db 128 dup (0)
FNsize dw 0
;
; Command line from PSP:80h will be copied to here work from
;
PSPstr db 128 dup (0)
;
; Command Line that will be passed to the EXEC function call of DOS
;
CLstr db 128 dup (0)
;
; Two FCB's that will be passed to the EXEC function call of DOS
;
FCB1 db 0
db 11 dup (' ')
db 0, 0, 0, 0
FCB2 db 0
db 11 dup (' ')
db 0, 0, 0, 0
COMstr db '.COM'
EXEstr db '.EXE'
;
INITmsg db 'STEPDOS Version 1.0'
db CR
db LF
db '$'
Memerr db CR
db LF
db 'Error Allocating Window Memory$'
Execmsg db CR
db LF
db 'Unable to execute target program$'
Findmsg db CR
db LF
db 'Unable to find target program$'
Umsg db CR
db LF
db 'Usage: STEPDOS <filename>$'
RegStr1 db ' AX BX CX DX DI SI BP SP'
db ' DS ES SS CS IP FL'
db 0
RegStr2 db '---- ---- ---- ---- ---- ---- ---- ----'
db ' ---- ---- ---- ---- ---- ----'
db 0
HlpStr1 db 'kip Current Function'
db 0
HlpStr2 db 'eturn Code'
db 0
HlpStr3 db ' - Non Stop'
db 0
HlpStr4 db 'Press Any Key To Continue'
db 0
Astr db 32 dup (0) ; string for converting ASCII characters
;
; Local Program Stack Area
;
db 128 dup (?)
Pstack EQU $
;
; Target Stack Area
;
db 128 dup (?)
Tstack EQU $
IF TESTING
Istr db 128 dup (' ')
Ostr db 'Output String'
db 0
ENDIF
IF TESTING
cli
mov AX,0
mov ES,AX
mov AX,OFFSET XTest
mov ES:[INT21OFF],AX
mov ES:[INT21OFF+2],CS
sti
ENDIF
IF TESTING
include test.asm
jmp execdn
ELSE
int 21h
ENDIF
Code ENDS
END Main